package article

import (
	"fmt"

	"github.com/Masterminds/squirrel"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/copier"
	"go-api-template/api/http"
	"go-api-template/api/models/system"
	"go-api-template/service"
)

type ListReq struct {
	Name     string   `json:"name"`
	Content  string   `json:"content"`
	TagNames []string `json:"tag_names"`
	http.PaginationReq
	http.JobReq
}
type ListResp struct {
	http.RespList[ListRespItem]
}
type ListRespItem struct {
	ID      string               `json:"id"`
	Name    string               `json:"name"`
	Status  system.ArticleStatus `json:"status"`
	Tags    []ListRespItemTag    `json:"tags"`
	Content string               `json:"content"`
}
type ListRespItemTag struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

func (req *ListReq) Request(ctx *gin.Context, s *service.Service) (http.Resp, error) {
	return req.Do(ctx, s)
}
func (req *ListReq) Do(ctx *gin.Context, s *service.Service) (resp http.Resp, err error) {
	var data ListResp
	var articles []system.Article

	req.query([]string{"sa.*"}, s, &articles)
	if !req.IsExport {
		data.Total = req.query([]string{`count(1)`}, s, nil)
	}
	for _, article := range articles {
		var articleTags []system.ArticleTag
		var item ListRespItem
		item.Tags = make([]ListRespItemTag, 0)
		_ = copier.Copy(&item, &article)
		s.Db.Where("article_id = ?", article.ID).Find(&articleTags)
		for _, tag := range articleTags {
			item.Tags = append(item.Tags, ListRespItemTag{
				ID:   tag.TagId,
				Name: tag.TagName,
			})
		}
		data.Items = append(data.Items, item)
	}

	resp.SetData(data)
	return
}
func (req *ListReq) query(selectS []string, s *service.Service, items *[]system.Article) (count int) {
	itemsSq := squirrel.Select(selectS...).
		From("system_article sa").
		LeftJoin("system_article_tag sat on sat.article_id = sa.id").
		GroupBy("sa.id")

	if req.Name != "" {
		itemsSq = itemsSq.Where("sa.name like ?", "%"+req.Name+"%")
	}
	if req.Content != "" {
		itemsSq = itemsSq.Where("sa.content like ?", "%"+req.Content+"%")
	}
	if len(req.TagNames) != 0 {
		itemsSq = itemsSq.Where("sat.name in ?", req.TagNames)
	}

	if items == nil {
		countSq := squirrel.Select("count(1)")
		toSql, value, _ := itemsSq.ToSql()
		countSq = countSq.From(fmt.Sprintf("(%s)t", toSql))
		toSql, _, _ = countSq.ToSql()
		s.Db.Raw(toSql, value...).Scan(&count)

	} else {
		if !req.IsExport {
			if req.PageSize != 0 && req.Page != 0 {
				itemsSq = itemsSq.Limit(uint64(req.PageSize)).Offset(uint64(req.PageSize * (req.Page - 1)))
			}
		}
		sql, value, _ := itemsSq.ToSql()
		s.Db.Raw(sql, value...).Debug().Scan(items)
	}
	return
}

type SaveReq struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Content string `json:"content"`
}

func (req *SaveReq) Request(ctx *gin.Context, s *service.Service) (http.Resp, error) {
	return req.Do(ctx, s)
}
func (req *SaveReq) Do(ctx *gin.Context, s *service.Service) (resp http.Resp, err error) {
	var data system.Article
	var article system.Article

	_ = copier.Copy(&article, req)

	if req.ID == "" {
		// 创建文章
		article.Status = system.ArticleStatusEdit
		s.Db.Create(&article)
	} else {
		// 编辑文章
		s.Db.Updates(&article)
	}
	_ = copier.Copy(&data, &article)

	resp.SetData(data)
	return
}

type DeleteReq struct {
	ID string `json:"id" binding:"required"`
}
type DeleteResp struct {
}

func (req *DeleteReq) Request(ctx *gin.Context, s *service.Service) (http.Resp, error) {
	return req.Do(ctx, s)
}
func (req *DeleteReq) Do(ctx *gin.Context, s *service.Service) (resp http.Resp, err error) {
	var data DeleteResp

	s.Db.Delete(&system.Article{}, "id = ?", req.ID)

	resp.SetData(data)
	return
}

type SaveTagReq struct {
	ArticleId string   `json:"article_id" binding:"required"`
	TagNames  []string `json:"tag_names" binding:"required"`
}
type SaveTagResp struct {
}

func (req *SaveTagReq) Request(ctx *gin.Context, s *service.Service) (http.Resp, error) {
	return req.Do(ctx, s)
}
func (req *SaveTagReq) Do(ctx *gin.Context, s *service.Service) (resp http.Resp, err error) {
	var data SaveTagResp

	s.Db.Debug().Unscoped().Delete(&system.ArticleTag{}, "article_id = ?", req.ArticleId)

	for _, name := range req.TagNames {
		tag := system.Tag{
			Name: name,
		}
		s.Db.Where("name = ?", name).First(&tag)
		if tag.ID == "" {
			s.Db.Create(&tag)
		}
		s.Db.Create(&system.ArticleTag{
			ArticleId: req.ArticleId,
			TagId:     tag.ID,
			TagName:   tag.Name,
			Status:    system.ArticleStatusEdit,
		})
	}

	resp.SetData(data)
	return
}
